﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OnlineGameLibrary.Game;
using OnlineGameLibrary.Contract;
using System.Diagnostics;
using System.Threading;
using OnlineGameLibrary.MessageEx;
using System.ServiceModel.Channels;
using KKSGameLibrary.Logic;
using KakaSongGame.Contract;
using System.Activities;
using System.Threading.Tasks;

namespace KakaSongGame
{
    public class KaKaSongGame1 : GameBase
    {
        TimeSpan playerwaitingtime;
        int puppetcount;

        CardSet _cardset;
        CardMap _cardmap;

        public KaKaSongGame1(GameRoom gameroom)
            : base(gameroom)
        {
            this.GameInfo = GlobalConst.GetGameInfo();

            playerwaitingtime = TimeSpan.FromSeconds((int)gameroom.GameConfig.ConfigDict[GlobalConst.PlayerWaitingTime_Config]);
            puppetcount = (int)gameroom.GameConfig.ConfigDict[GlobalConst.PlayerPuppetCount_Config];

            _cardset = new CardSet();

            var gplist = from p in GameRoom.Players
                         select new GamePlayer(p.PlayerID,p.PlayerDisplayName);
            _cardmap = new CardMap(gplist.ToList(), puppetcount);
        }

        public override void OnPlayerLeave(string playerid)
        {
            //lock (GameRoom.Players)
            //{
            //    if (CurrentPlayer.PlayerID == playerid)
            //    {
            //        int playerindex = GameRoom.Players.IndexOf(CurrentPlayer);
            //        Debug.Assert(playerindex >= 0);

            //        playerindex--;
            //        if (playerindex < 0)
            //            playerindex = GameRoom.Players.Count - 1;

            //        CurrentPlayer = GameRoom.Players[playerindex];
            //    }
            //}
        }

        public override void BeginRun(Action<GameEndEventArgs> onend)
        {
            ThreadPool.QueueUserWorkItem(
                new WaitCallback(Run),
                onend);
        }

        //void Run(object o)
        //{
        //    var dict = new Dictionary<string, object>();
        //    dict["Game"] = this;
        //    WorkflowInvoker.Invoke(new CarcassonneActivity(), dict);
        //}

        //void func()
        //{
        //    var curcard = _cardset.GetCard();
        //    var curgameplayer = this._cardmap.Players.First(gp => gp.ID == curplayer.PlayerID);

        //    Message req_msg = KKSGameMessageDefines.REQUEST_PUT_CARD
        //    .CreateMessage(curcard)
        //    .SetDueTime(DateTime.Now.Add(playerwaitingtime))
        //    .SetAudience(new List<string> { curplayer.PlayerID });
        //    BoardcastMessageInRoom(req_msg);

        //}

        void Run(object o)
        {
            curplayer = GameRoom.Players[0];
            do
            {
                if (curplayer == null)
                {
                    HandleGameEnd(GameResult.Terminated, o as Action<GameEndEventArgs>);
                    break;
                }

                if (_cardset.Count == 0)
                {
                    HandleGameEnd(GameResult.Completed, o as Action<GameEndEventArgs>);
                    break;
                }

                var curcard = _cardset.GetCard();
                var curgameplayer = this._cardmap.Players.First(gp => gp.ID == curplayer.PlayerID);

                // boardcast message to request the in-turn player to take action
                ///////////////////////////////////////////////////////////////////////
                Message req_msg = KKSGameMessageDefines.REQUEST_PUT_CARD
                    .CreateMessage(curcard)
                    .SetDueTime(DateTime.Now.Add(playerwaitingtime))
                    .SetAudience(new List<string> { curplayer.PlayerID });
                BoardcastMessageInRoom(req_msg);

                // listen on the in-turn player's channel to receive message
                ///////////////////////////////////////////////////////////////////////
                MessageContent response_msg_content;
                var result = curplayer.ReceiveMessageFromPlayer(
                    playerwaitingtime,
                    KKSGameMessageDefines.RESPONSE_PUT_CARD,
                    out response_msg_content);

                // handle player action
                ///////////////////////////////////////////////////////////////////////
                CardInMap curcardinmap = null;
                Message re_response_msg = null;
                if (result)
                {
                    curcardinmap = response_msg_content.MessageBodyContent as CardInMap;

                    // verify user action!
                    if (curcardinmap.Card.IsEqual(curcard)
                        && _cardmap.TestSetCard(curcardinmap))
                    {
                        // sync server game logic
                        _cardmap.SetCard(curcardinmap, curgameplayer);

                        re_response_msg = KKSGameMessageDefines.RESPONSE_PUT_CARD
                            .CreateMessage(curcardinmap)
                            .SetAudience(new List<string> { curplayer.PlayerID });
                    }
                }
                if (re_response_msg == null)
                {
                    re_response_msg = KKSGameMessageDefines.RESPONSE_PUT_CARD
                        .CreateMessage(null)
                        .SetAudience(new List<string> { curplayer.PlayerID });
                }

                // boardcast the handled player action message
                // player is possible be removed from gameroom here, be cautious
                ///////////////////////////////////////////////////////////////////////
                BoardcastMessageInRoom(re_response_msg);

                // put puppet
                if (curgameplayer.PuppetRemain > 0)
                {

                    // boardcast message to request the in-turn player to take action
                    ///////////////////////////////////////////////////////////////////////
                    Message req_msg2 = KKSGameMessageDefines.REQUEST_PUT_PUPPET
                        .CreateMessage(null)
                        .SetDueTime(DateTime.Now.Add(playerwaitingtime))
                        .SetAudience(new List<string> { curplayer.PlayerID });
                    BoardcastMessageInRoom(req_msg2);

                    // listen on the in-turn player's channel to receive message
                    ///////////////////////////////////////////////////////////////////////
                    MessageContent response_msg_content2;
                    var result2 = curplayer.ReceiveMessageFromPlayer(
                        playerwaitingtime,
                        KKSGameMessageDefines.RESPONSE_PUT_PUPPET,
                        out response_msg_content2);

                    // handle player action
                    ///////////////////////////////////////////////////////////////////////
                    PuppetOperation curpuppet = null;
                    Message re_response_msg2 = null;
                    if (result2)
                    {
                        curpuppet = response_msg_content2.MessageBodyContent as PuppetOperation;

                        if (!curpuppet.IsPutPuppet)
                            re_response_msg2 = KKSGameMessageDefines.RESPONSE_PUT_PUPPET
                                .CreateMessage(curpuppet)
                                .SetAudience(new List<string> { curplayer.PlayerID });
                        else
                        {
                            var region = _cardmap.GetRegion(curpuppet.Row, curpuppet.Column, curpuppet.Direction);

                            // verify user action!
                            if (region != null && _cardmap.TestSetOwner(region, curgameplayer))
                            {
                                // sync server game logic
                                _cardmap.SetOwner(curpuppet.Row, curpuppet.Column, curpuppet.Direction, curgameplayer);

                                // create message
                                re_response_msg2 = KKSGameMessageDefines.RESPONSE_PUT_PUPPET
                                    .CreateMessage(curpuppet)
                                    .SetAudience(new List<string> { curplayer.PlayerID });
                            }
                        }
                    }
                    if (re_response_msg2 == null)
                    {
                        re_response_msg2 = KKSGameMessageDefines.RESPONSE_PUT_PUPPET
                            .CreateMessage(null)
                            .SetAudience(new List<string> { curplayer.PlayerID });
                    }

                    // boardcast the handled player action message
                    // player is possible be removed from gameroom here, be cautious
                    ///////////////////////////////////////////////////////////////////////
                    BoardcastMessageInRoom(re_response_msg2);

                }

                // get next player
                GetNext();
            }
            while (true);
        }
        

        void HandleGameEnd(GameResult result, Action<GameEndEventArgs> onend)
        {
            var re_msg = KKSGameMessageDefines.GAME_END
                        .CreateMessage(result);
            BoardcastMessageInRoom(re_msg);

            onend(new GameEndEventArgs
            {
                GameRoom = this.GameRoom,
                Result = result
            });
        }

        void BoardcastMessageInRoom(Message msg)
        {
            var buffer = msg.CreateBufferedCopy(GameRoom.Players.Count);
            lock (GameRoom.Players)
            {
                foreach (var player in GameRoom.Players)
                {
                    var newmsg = buffer.CreateMessage();
                    player.SendMessageToPlayer(newmsg);
                }
            }
        }

        Player curplayer;
        public Player GetNext()
        {
            lock (GameRoom.Players)
            {
                if (GameRoom.Players.Count == 0)
                {
                    curplayer = null;
                    return null;
                }

                int playerindex = GameRoom.Players.IndexOf(curplayer);
                Debug.Assert(playerindex >= 0);

                playerindex++;
                if (playerindex >= GameRoom.Players.Count)
                    playerindex = 0;

                curplayer = GameRoom.Players[playerindex];
            }
            return curplayer;
        }

        public override void StopRun()
        {
            throw new NotImplementedException();
        }
    }
}
